(function (fruit, dom, cache, support, browser, util, global, document) {
    var rTableElement = /^t(?:able|d|h)$/i;
    var AUTO = 'auto',
        WIDTH = 'width',
        HEIGHT = 'height',
        MARGIN = 'margin',
        PADDING = 'padding',
        BORDER = 'border',
        TOP = 'top',
        RIGHT = 'right',
        BOTTOM = 'bottom',
        LEFT = 'left',
        FIXED = 'fixed';
    var isIE8 = (browser.ie === 8),
        borderMap = {
            thin:(isIE8) ? '1px' : '2px',
            medium:(isIE8) ? '3px' : '4px',
            thick:(isIE8) ? '5px' : '6px'
        },
        sizeMap = {
            width:['Width', LEFT, RIGHT],
            height:['Height', TOP, BOTTOM]
        };

    function getBoxWidth(inBox, inElement, inDirection) {
        var boxWidth, styleResult;
        switch (inBox) {
            case PADDING:
            case MARGIN:
                styleResult = dom.getStyle(inElement, inBox + inDirection);
                boxWidth = parseFloat(styleResult);
                break;
            default:
                styleResult = dom.getStyle(inElement, 'border-' + inDirection + '-width');
                if (browser.firefox) {
                    if (rTableElement.test(inElement.tagName)) {
                        styleResult = 0;
                    }
                }
                boxWidth = parseFloat(styleResult) || borderMap[styleResult];
        }
        return boxWidth || 0;
    }

    function getBoxWidths(inBox, inElement) {
        return {
            top:getBoxWidth(inBox, inElement, TOP),
            right:getBoxWidth(inBox, inElement, RIGHT),
            bottom:getBoxWidth(inBox, inElement, BOTTOM),
            left:getBoxWidth(inBox, inElement, LEFT)
        };
    }

    function getSize(inElement, inName) {
        var result = dom.getStyle(inElement, inName),
            map = sizeMap[inName];
        var border, padding;
        if (result === AUTO) {
            border = getBoxWidth(BORDER, inElement, map[1]) + getBoxWidth(BORDER, inElement, map[2]);
            padding = getBoxWidth(PADDING, inElement, map[1]) + getBoxWidth(PADDING, inElement, map[2]);
            return inElement['offset' + map[0]] - border - padding;
        } else {
            return parseFloat(result);
        }
    }

    function setSize(inElement, inName, inValue) {
        var size = 0, value = inValue;
        dom.setStyle(inElement, inName, value);
        size = (inName === HEIGHT) ? inElement.offsetHeight : inElement.offsetWidth;
        if (size > value) {
            value = value - (size - value);
            dom.setStyle(inElement, inName, value);
        }
    }

    var position = fruit.position = {
        attrWidth:function (inBox, inElement, inDirection) {
            if (inDirection) {
                return getBoxWidth(inBox, inElement, inDirection);
            } else {
                return getBoxWidths(inBox, inElement);
            }
        },
        getWidth:function (inElement) {
            return getSize(inElement, WIDTH);
        },
        getHeight:function (inElement) {
            return getSize(inElement, HEIGHT);
        },
        getSize:function (inElement) {
            return {
                width:inElement.offsetWidth,
                height:inElement.offsetHeight
            };
        },
        getBound:function (inElement, inDocument) {
            var box = inElement.getBoundingClientRect(),
                root = dom.getRoot(inDocument || document),
                clientTop = root.clientTop || 0,
                clientLeft = root.clientLeft || 0;
            return {
                left:box.left - clientLeft,
                top:box.top - clientTop,
                width:box.width,
                height:box.height
            };
        },
        setWidth:function (inElement, inValue) {
            setSize(inElement, WIDTH, inValue);
        },
        setHeight:function (inElement, inValue) {
            setSize(inElement, HEIGHT, inValue);
        },
        setSize:function (element, obj) {
            setSize(element, 'width', obj.width);
            setSize(element, 'height', obj.height);
        },
        docRect:function (inDocument) {
            var doc = inDocument || document;
            var window = dom.getWindow(doc),
                root = dom.getRoot(doc),
                height = window.innerHeight || 0,
                width = window.innerWidth || 0,
                scrollW = root.scrollWidth,
                scrollH = root.scrollHeight,
                scrollXY = position.getScroll(inDocument);
            if (browser.compatMode && !browser.opera) { // IE, Gecko
                width = root.clientWidth;
                height = root.clientHeight;
            }
            scrollW = Math.max(scrollW, width);
            scrollH = Math.max(scrollH, height);
            return {
                width:width,
                height:height,
                scrollWidth:scrollW,
                scrollHeight:scrollH,
                scrollX:scrollXY.left,
                scrollY:scrollXY.top
            };
        },
        getScroll:function (inDocument) {
            var doc = inDocument || document;
            var root = dom.getRoot(doc);
            return {
                left:Math.max((global.pageXOffset || 0), root.scrollLeft),
                top:Math.max((global.pageYOffset || 0), root.scrollTop)
            };
        },
        setScroll:function (left, top, doc) {
            var win = dom.getWindow(doc);
            win.scrollTo(left, top);
        },
        getOffset:function (inElement, inDocument) {
            var doc = inDocument || document;
            var box = inElement.getBoundingClientRect(),
                root = dom.getRoot(doc),
                clientTop = root.clientTop || 0,
                clientLeft = root.clientLeft || 0;
            return {
                'top':box.top + (global.pageYOffset || root.scrollTop ) - clientTop,
                'left':box.left + (global.pageXOffset || root.scrollLeft ) - clientLeft
            };
        },
        setOffset:function (inElement, inStyleObj) {
            var elPosition = dom.getStyle(inElement, 'position'), styleObj = inStyleObj;
            var scroll = this.getScroll();
            if (elPosition === FIXED) {
                styleObj = {
                    left:parseFloat(styleObj) + scroll.scrollX,
                    top:parseFloat(styleObj) + scroll.scrollY
                };
            }
            dom.setStyles(inElement, styleObj);
        },
        margin:function (inElement, inDirection) {
            return position.attrWidth(MARGIN, inElement, inDirection);
        },
        padding:function (inElement, inDirection) {
            return position.attrWidth(PADDING, inElement, inDirection);
        },
        border:function (inElement, inDirection) {
            return position.attrWidth(BORDER, inElement, inDirection);
        }
    };
}(fruit, fruit.dom, fruit.cache, fruit.support, fruit.browser, _, window, document));